//package com.tiancheng.trade.payment.task.ums;
//
//import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
//import com.tiancheng.trade.commom.data.Result;
//import com.tiancheng.trade.commom.exception.BusinessException;
//import com.tiancheng.trade.commom.exception.error.BusinessErrorInfoEnum;
//import com.tiancheng.trade.payment.bo.SettleDistErrorBO;
//import com.tiancheng.trade.payment.channel.bo.PaymentFlowDetailBO;
//import com.tiancheng.trade.payment.channel.bo.RefundSettleBO;
//import com.tiancheng.trade.payment.channel.bo.StatisticsSubOrderRefundBo;
//import com.tiancheng.trade.payment.configuration.UmsAllConfigs;
//import com.tiancheng.trade.commom.core.enums.PaymentChannelEnum;
//import com.tiancheng.trade.commom.core.enums.SettleStatusEnum;
//import com.tiancheng.trade.payment.feign.FileUpload;
//import com.tiancheng.trade.payment.feign.MerchantService;
//import com.tiancheng.trade.commom.web.model.request.MerchantChannelRequestDTO;
//import com.tiancheng.trade.commom.web.model.response.MerchantChannelResponseDTO;
//import com.tiancheng.trade.payment.model.*;
//import com.tiancheng.trade.payment.service.*;
//import com.tiancheng.trade.payment.task.ums.bo.DownloadFileBo;
//import com.tiancheng.trade.payment.task.ums.bo.FileRetBo;
//import com.tiancheng.trade.payment.task.ums.bo.SettleDetailBo;
//import com.tiancheng.trade.payment.task.ums.bo.SettleFileBo;
//import com.tiancheng.trade.payment.util.CommonUtil;
//import com.tiancheng.trade.payment.util.DateTimeUtil;
//import com.tiancheng.trade.payment.util.JsonUtil;
//import com.tiancheng.trade.payment.util.TxtUtil;
//import com.xxl.job.core.biz.model.ReturnT;
//import com.xxl.job.core.handler.annotation.XxlJob;
//import lombok.extern.slf4j.Slf4j;
//import org.apache.commons.collections4.MapUtils;
//import org.apache.commons.lang3.StringUtils;
//import org.redisson.api.RLock;
//import org.redisson.api.RedissonClient;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.scheduling.annotation.Scheduled;
//import org.springframework.stereotype.Component;
//import org.springframework.transaction.annotation.Transactional;
//import org.springframework.util.CollectionUtils;
//
//import java.io.File;
//import java.time.Instant;
//import java.time.LocalDate;
//import java.time.LocalDateTime;
//import java.time.format.DateTimeFormatter;
//import java.util.*;
//import java.util.concurrent.TimeUnit;
//import java.util.concurrent.atomic.AtomicInteger;
//import java.util.stream.Collectors;
//
//import static com.tiancheng.trade.payment.util.CommonUtil.splitMap;
//import static com.tiancheng.trade.commom.core.utils.RandomCharSequenceUtil.getRandomCharSequence;
//
///**
// * 银联商务清分自动任务
// *
// * @author kellen
// * @date 2024/11/9
// */
//@Component
//@Slf4j
//public class UmsSettleTask {
//    /**
//     * 单个文件明细数不超过1万条
//     */
//    private static final int FILE_MAX = 9000;
//    private static final String LOST_RULE = "缺少清分规则";
//    private static final String LOST_MERCHANT = "缺少商户信息或商户企业用户号";
//    private static final String LESS_APPR_AMOUNT = "划付轧差为负";
//    private static final String LESS_DIST_AMOUNT = "分账轧差为负";
//    private static final String SETTLE_ERROR = "ERROR";
//    private static final String SETTLE_ING = "ING";
//    private static final String SETTLE_SUCCESS = "SUCCESS";
//    // 回盘文件查找判断时间
//    public static final String SETTLE_TIME = "05:00:00";
//    @Autowired
//    private PaymentFlowDetailService flowDetailService;
//    @Autowired
//    private MerchantService merchantService;
//    @Autowired
//    private SettleMatchService settleMatchService;
//    @Autowired
//    private SettleFileService settleFileService;
//    @Autowired
//    private SettleDetailService settleDetailService;
//    @Autowired
//    private SettlePlatformService settlePlatformService;
//    @Autowired
//    private UmsAllConfigs umsAllConfigs;
//    @Autowired
//    private FileUpload fileUpload;
//    @Autowired
//    private RedissonClient redissonClient;
//    @Autowired
//    private PaymentRefundService refundService;
//    @Autowired
//    private PaymentRefundFlowDetailService refundFlowDetailService;
//    @Autowired
//    private SettleMatchRefundService settleMatchRefundService;
//    @Autowired
//    private SettleDistErrorService settleDistErrorService;
//
//    /**
//     * 银联资管清分自动任务
//     * 以商户为维度聚合指令，一个商户一条指令
//     * 只上传（并记录到数据库）可以正常清分的订单，非正常订单滞留并记录
//     *
//     * @param param {@link String}
//     * @return {@link ReturnT<String>}
//     */
//    @Transactional
//    @XxlJob("uploadUmsSettleAppropriation")
//    public ReturnT<String> uploadSettle(String param) {
//        log.info("自动清分任务开始执行：{}", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
//        // 同时刻不允许有多个任务处理相同数据
//        RLock lock = redissonClient.getLock("UMS_UPLOAD_SETTLE");
//        boolean isLock;
//        try {
//            isLock = lock.tryLock(30L, TimeUnit.MINUTES);
//            if (!isLock) {
//                log.error("自动清分任务执行结果：锁失败！");
//                return ReturnT.SUCCESS;
//            }
//            // 1、聚合子订单流水中应清分商户、商品编码
//            List<PaymentFlowDetail> details = flowDetailService.distinctSettle(LocalDate.now());
//            if (details.isEmpty()) {
//                log.info("自动清分任务执行结果：无应清分数据！");
//                return ReturnT.SUCCESS;
//            }
//            // 2.1、查询商品清分规则 key=productId, value=SettlementRuleDTO
//            HashSet<Map<String, String>> products = new HashSet<>();
//            for (PaymentFlowDetail detail : details) {
//                Map<String, String> p = new HashMap<>();
//                p.put("merchant_code", detail.getMerchantCode());
//                p.put("product_code", detail.getProductId());
//                products.add(p);
//            }
//            Map<String, SettlementRuleDTO> productRuleMap = settlePlatformService.getSettlementRuleMap(products);
//            products.clear();
//            products = null;
//            // 2.2、查询商户清分规则 key=merchantCode, value=SettlementRuleDTO
//            Map<String, SettlementRuleDTO> merchantRuleMap = settlePlatformService.getSettlementRuleMapByMerchantCods(details.stream().map(PaymentFlowDetail::getMerchantCode).collect(Collectors.toSet()));
//            if (MapUtils.isEmpty(productRuleMap) && MapUtils.isEmpty(merchantRuleMap)) {
//                log.error("自动清分任务执行结果：缺失清分规则！");
//                return ReturnT.SUCCESS;
//            }
//            log.info("清分任务获取到清分规则 商品纬度清分规则：{}条,商户纬度清分规则{}条", productRuleMap.size(), merchantRuleMap.size());
//
//            // 3、查询企业用户号    merchantMap: key=merchantCode, value=MerchantChannelResponseDTO
//            Result<List<MerchantChannelResponseDTO>> merRepResult = merchantService.listByMerchantCodeAndChannel(
//                    details.stream().map(PaymentFlowDetail::getMerchantCode).collect(Collectors.toSet())
//                            .stream().map(merchantCode -> new MerchantChannelRequestDTO(merchantCode, PaymentChannelEnum.UMS.getCode())).collect(Collectors.toList())
//            );
//            if (merRepResult.getData().size() < 1) {
//                log.error("自动清分任务执行结果：缺少渠道商户信息！");
//                return ReturnT.SUCCESS;
//            }
//            Map<String, MerchantChannelResponseDTO> merchantMap = new HashMap<>();
//            for (MerchantChannelResponseDTO datum : merRepResult.getData()) {
//                merchantMap.put(datum.getMerchantCode(), datum);
//                if (StringUtils.isNotEmpty(datum.getMerchantCodeBusiness())) {
//                    merchantMap.put(datum.getMerchantCodeBusiness(), datum);
//                }
//            }
//            log.info("自动分账：获取到商户信息：{}", JsonUtil.toJsonString(merchantMap));
//            details.clear();
//            details = null;
//            merRepResult = null;
//            // 4、开始分批次处理清分指令明细数据
//            Map<String, SettleDetail> settleDetailMap = new HashMap<>(); // 清分文件指令明细
//            /*
//             * 清分数据处理
//             * - 商户维度聚合划付资金、分账资金
//             * - settleDetailMap收集清分指令（缺少划付-文件名、分账-文件名）
//             */
//            handleSettleData(productRuleMap, merchantRuleMap, merchantMap, settleDetailMap);
//            productRuleMap.clear();
//            productRuleMap = null;
//            merchantRuleMap.clear();
//            merchantRuleMap = null;
//            merchantMap.clear();
//            merchantMap = null;
//            // 5、清分文件分切生成
//            List<File> apprFiles = new ArrayList<>(); // 划付文件
//            List<File> distFiles = new ArrayList<>(); // 分账文件
//            /*
//             * 文件处理，每个文件最多10000条数据量，本程序设定最多9001条
//             * - 生成划付文件和分账文件
//             * - 补充settleDetailMap中划付-文件名、分账-文件名
//             */
//            handleSettleFile(settleDetailMap, apprFiles, distFiles);
//            settleDetailMap.clear();
//            settleDetailMap = null;
//            // 6、上传文件
//            String path = umsAllConfigs.getUmsSettleDirPre() + "/" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); // 服务器文件目录
//            UmsFileHandler.parallelUploadFile(path, apprFiles, distFiles);
//            log.info("上传文件至银联服务器成功！");
//            apprFiles.clear();
//            apprFiles = null;
//            distFiles.clear();
//            distFiles = null;
//        } catch (Exception e) {
//            log.error("银联资管清分自动任务执行失败：", e);
//            throw new BusinessException(BusinessErrorInfoEnum.UMS_SETTLE_ERROR, null, "银联资管清分自动任务执行失败", e);
//        } finally {
//            if (lock.isLocked()) {
//                lock.unlock();
//            }
//        }
//        return ReturnT.SUCCESS;
//    }
//
//    /**
//     * 自动清除本地临时文件
//     * cron表达式：秒 分 时 天 月 周 年
//     */
//    @Scheduled(cron = "0 0 23 * * ?")
//    public void cleanUploadFile() {
//        File file = new File("./");
//        if (!file.exists())
//            return;
//        String[] fileNames = file.list();
//        if (null == fileNames || fileNames.length < 1)
//            return;
//        for (String fileName : fileNames) {
//            if ((fileName.startsWith("04_") || fileName.startsWith("02_") || fileName.startsWith("09_")) && fileName.contains(".txt"))
//                new File(fileName).delete();
//        }
//    }
//
//    /**
//     * 银联资管-划付回盘文件处理
//     * - 获取前2天2点（包含）到前1天2点（不包含）之间发生改动的文件
//     *
//     * @param param {@link String} 指定的某个时间起
//     * @return {@link ReturnT<String>}
//     */
//    @XxlJob("umsSettleCounterofferHandle")
//    public ReturnT<String> umsSettleCounterofferHandle(String param) {
//        // 1、文件改动时间基点: 时间固定到位当天凌晨5点到前一天凌晨5点
//        LocalDateTime startDate = DateTimeUtil.string2LocalDateTime(DateTimeUtil.temporalFormat2String(LocalDateTime.now(), "yyyy-MM-dd") + " " + SETTLE_TIME, "yyyy-MM-dd HH:mm:ss");
//        if (!StringUtils.isEmpty(param)) {
//            param += (" " + SETTLE_TIME);
//            startDate = DateTimeUtil.string2LocalDateTime(param, "yyyy-MM-dd HH:mm:ss");
//        }
//        log.info("开始处理回盘划付文件，任务开始时间：{}", DateTimeUtil.temporalFormat2String(startDate, "yyyy-MM-dd HH:mm:ss"));
//        try {
//            // 2、下载目标文件到目标服务器目标目录，并返回文件名信息
//            List<DownloadFileBo> files = UmsFileHandler.downloadFile(startDate, "/" + umsAllConfigs.getUmsSettleDirPre() + "/", fileUpload);
//            if (files.isEmpty()) {
//                return ReturnT.SUCCESS;
//            }
//            // 3、获取文件内容
//            List<FileRetBo> fileRetBos = UmsFileHandler.readRemoteFiles(files, "final_");
//            if (fileRetBos.isEmpty()) {
//                log.info("划付回盘文件处理，未获取到需要处理的文件!");
//                return ReturnT.SUCCESS;
//            }
//            Set<String> fileNames = fileRetBos.stream().map(fileRetBo -> getSourceFIleName(fileRetBo.getFileName())).collect(Collectors.toSet());
//            List<SettleFile> settleFiles = settleFileService.findByFileNames(fileNames);
//            BusinessErrorInfoEnum.ASSET_MANAGEMENT_NOT_FOUNT_APPROPRIATIONS_FILE.assertIsTrue(!CollectionUtils.isEmpty(settleFiles));
//            List<SettleFileBo> settleFileBos = new ArrayList<>();
//            // 4、开始对文件处理
//            for (FileRetBo fileRetBo : fileRetBos) {
//                // 汇总行
//                List<Object[]> summaryRowData = fileRetBo.getRowData(0, 1);
//                if (CollectionUtils.isEmpty(summaryRowData) || null == summaryRowData.get(0)) {
//                    log.error("文件没有内容，汇总行为空，文件名称：{}", fileRetBo.getFileName());
//                    //没有汇总信息
//                    continue;
//                }
//                // 解析数据
//                List<SettleFile> collect = new ArrayList<>();
//                String fileName = fileRetBo.getFileName().replace("final_", "").replace(".ret", "");
//                for (SettleFile settleFile : settleFiles) {
//                    if (StringUtils.isNotBlank(settleFile.getApprFileName()) && settleFile.getApprFileName().equals(fileName)) {
//                        collect.add(settleFile);
//                    }
//                    if (StringUtils.isNotBlank(settleFile.getDistFileName()) && settleFile.getDistFileName().equals(fileName)) {
//                        collect.add(settleFile);
//                    }
//                }
//                if (CollectionUtils.isEmpty(collect)) {
//                    log.error("未查询到分账、划付记录，文件名称：{}", fileName);
//                    continue;
//                }
//
//                // 文件明细处理
//
//                List<Object[]> detailRowData = fileRetBo.getRowData(1, fileRetBo.getData().length);
//                if (CollectionUtils.isEmpty(detailRowData)) {
//                    log.error("文件没有内容，明细行为空，文件名称：{}", fileRetBo.getFileName());
//                    settleFileService.updateNoneSettle(getSettleFileBo(fileRetBo, summaryRowData, collect));
//                    //没有详细信息
//                } else {
//                    SettleFileBo settleFileBo = getSettleFileBo(fileRetBo, summaryRowData, collect);
//                    settleFileBos.add(settleFileBo);
//                }
//
//            }
//            log.info("更新划付回盘文件解析结果：{}", JsonUtil.toJsonString(settleFileBos));
//            // 5、保存划付文件结果
//            settleFileService.saveSettleApprRet(settleFileBos);
//        } catch (Exception e) {
//            log.error("划付回盘文件处理异常：{}", e.getMessage());
//            return ReturnT.FAIL;
//        }
//
//        return ReturnT.SUCCESS;
//    }
//
//    /**
//     * 获取源文件名称
//     *
//     * @param fileName {@link String}
//     * @return {@link String}
//     */
//    private String getSourceFIleName(String fileName) {
//        return fileName.replace("final_", "").replace(".ret", "").replace(".chk", "");
//    }
//
//    private SettleFileBo getSettleFileBo(FileRetBo fileRetBo, List<Object[]> summaryRowData, List<SettleFile> collect) {
//        SettleFileBo settleFileBo = new SettleFileBo();
//        settleFileBo.setId(collect.get(0).getId());
//        if (getSourceFIleName(fileRetBo.getFileName()).startsWith("02_" + umsAllConfigs.getGroupCode())) {
//            //划付文件处理
//            settleFileBo.setApprFileName(collect.get(0).getApprFileName());
//            settleFileBo.setGroupCode(String.valueOf(summaryRowData.get(0)[0]));// 商户集团编号
//            settleFileBo.setChannel(PaymentChannelEnum.UMS.getCode());// 渠道
//            settleFileBo.setApprSuccessNum(Integer.valueOf(String.valueOf(summaryRowData.get(0)[1])));//成功划付笔数
//            settleFileBo.setApprSuccessAmount(Long.valueOf(String.valueOf(summaryRowData.get(0)[2])));//成功划付金额
//            settleFileBo.setApprSuccessPart(Integer.valueOf(String.valueOf(summaryRowData.get(0)[3])));//部分成功划付笔数
//            settleFileBo.setApprSuccessPartAmount(Long.valueOf(String.valueOf(summaryRowData.get(0)[4])));//部分成功划付金额
//            settleFileBo.setApprFailPartAmount(Long.valueOf(String.valueOf(summaryRowData.get(0)[5])));//部分成功划付失败金额
//            settleFileBo.setApprFailNum(Integer.valueOf(String.valueOf(summaryRowData.get(0)[6])));//划付失败笔数
//            settleFileBo.setApprFailAmount(Long.valueOf(String.valueOf(summaryRowData.get(0)[7])));//失败金额
//            settleFileBo.setApprActualAmount(Long.valueOf(String.valueOf(summaryRowData.get(0)[8])));//实际成功划付金额
//            settleFileBo.setApprServiceFee(Long.valueOf(String.valueOf(summaryRowData.get(0)[9])));//手续费金额
//            settleFileBo.setApprHandleNum(Integer.valueOf(String.valueOf(summaryRowData.get(0)[10])));//处理中笔数
//            settleFileBo.setApprHandleAmount(Long.valueOf(String.valueOf(summaryRowData.get(0)[11])));//处理中金额
//            settleFileBo.setApprBackFileUrl(fileRetBo.getDownloadPath());
//            // 指令明细处理
//            List<Object[]> sourceDetailData = fileRetBo.getRowData(1, fileRetBo.getData().length);
//            if (!CollectionUtils.isEmpty(sourceDetailData)) {
//                List<SettleDetailBo> settleDetailBos = new ArrayList<>(sourceDetailData.size());
//                for (Object[] sourceDetailDatum : sourceDetailData) {
//                    SettleDetailBo adb = new SettleDetailBo();
//                    adb.setApprFileName(collect.get(0).getApprFileName());
//                    adb.setApprId(String.valueOf(sourceDetailDatum[0]));//划付指令ID
//                    adb.setApprEnterpriseCode(String.valueOf(sourceDetailDatum[1]));//企业用户号
//                    adb.setApprCurrencyType(String.valueOf(sourceDetailDatum[2]));//划付金额类型,0 – 固定金额
//                    adb.setApprAmount(getLong(sourceDetailDatum[3]));//
//                    adb.setSucAmount(getLong(sourceDetailDatum[4]));
//                    adb.setApprStatus(SettleStatusEnum.getCodeByUmsCode(String.valueOf(sourceDetailDatum[5])).getCode());
//                    adb.setApprFailReason(String.valueOf(sourceDetailDatum[6]));
//                    adb.setOutId(String.valueOf(sourceDetailDatum[7]));
//                    adb.setSettlementAmount(getLong(sourceDetailDatum[8]));
//                    adb.setBusinessHandleFee(getLong(sourceDetailDatum[9]));
//                    adb.setUpdateConditionStatus(SettleStatusEnum.ING.getCode());
//                    settleDetailBos.add(adb);
//                }
//                settleFileBo.setSettleDetailBos(settleDetailBos);
//            }
//
//        } else if (getSourceFIleName(fileRetBo.getFileName()).startsWith("04_" + umsAllConfigs.getGroupCode())) {
//            //分账文件处理
//            // 商户集团编号
//            settleFileBo.setGroupCode(String.valueOf(summaryRowData.get(0)[0]));//商户集团编号
//            settleFileBo.setDistSuccessNum(Integer.valueOf(String.valueOf(summaryRowData.get(0)[1])));//成功分账笔数
//            settleFileBo.setDistSuccessAmount(Long.valueOf(String.valueOf(summaryRowData.get(0)[2])));//成功分账金额
//            settleFileBo.setDistSuccessPart(Integer.valueOf(String.valueOf(summaryRowData.get(0)[3])));//部分成功分账笔数
//            settleFileBo.setDistSuccessPartAmount(Long.valueOf(String.valueOf(summaryRowData.get(0)[4])));//部分成功分账金额
//            settleFileBo.setDistBackFileUrl(fileRetBo.getDownloadPath());
//            List<Object[]> sourceDetailData = fileRetBo.getRowData(1, fileRetBo.getData().length);
//            if (!CollectionUtils.isEmpty(sourceDetailData)) {
//                List<SettleDetailBo> settleDetailBos = new ArrayList<>(sourceDetailData.size());
//                for (Object[] sourceDetailDatum : sourceDetailData) {
//                    SettleDetailBo adb = new SettleDetailBo();
//                    adb.setDistId(String.valueOf(sourceDetailDatum[0]));//分账指令ID
//                    adb.setDistEnterpriseCode(String.valueOf(sourceDetailDatum[1]));//企业用户号
//                    adb.setDistCurrencyType(String.valueOf(sourceDetailDatum[2]));//分账金额类型
//                    adb.setDistAmount(Long.valueOf(String.valueOf(sourceDetailDatum[4])));//分账金额
//                    adb.setDistStatus(SettleStatusEnum.getCodeByUmsCode(String.valueOf(sourceDetailDatum[5])).getCode());
//                    adb.setDistFailReason(String.valueOf(sourceDetailDatum[6]));
//                    adb.setUpdateDistConditionStatus(SettleStatusEnum.ING.getCode());
//                    settleDetailBos.add(adb);
//                }
//                settleFileBo.setSettleDetailBos(settleDetailBos);
//            }
//        }
//
//        return settleFileBo;
//    }
//
//    private Long getLong(Object obj) {
//        if (obj == null || StringUtils.isEmpty(obj.toString())) {
//            return null;
//        }
//        return Long.valueOf(obj.toString());
//    }
//
//    /**
//     * 分批次处理数据
//     * - 商户维度聚合划付资金、分账资金
//     * - settleDetailMap收集清分指令（缺少划付-文件名、分账-文件名、退款金额、划付-金额、退款返还的分账金额、分账-金额）
//     * - 数据库记录每清分指令所对应的支付流水明细，更新流水明细
//     * - 数据库记录流水状态
//     *
//     * @param productRuleMap  {@link Map} 商品清分规则
//     * @param merchantRuleMap {@link Map} 商户清分规则
//     * @param merchantMap     {@link Map} 商户信息
//     * @param settleDetailMap {@link Map} 清分指令明细
//     */
//    private void handleSettleData(Map<String, SettlementRuleDTO> productRuleMap,
//                                  Map<String, SettlementRuleDTO> merchantRuleMap,
//                                  Map<String, MerchantChannelResponseDTO> merchantMap,
//                                  Map<String, SettleDetail> settleDetailMap) {
//        List<SettleMatch> settleMatches = new ArrayList<>(1000); // 可正常清分指令-流水明细映射记录
//        List<Long> lrList = new ArrayList<>(100); // 不可正常清分指令明细记录：缺少清分规则
//        List<Long> lmList = new ArrayList<>(100); // 不可正常清分指令明细记录：缺少商户信息
//        Map<String, List<Long>> merchantFlowDetailIds = new HashMap<>(1000); // 记录每个商户可正常清分的支付子流水id
//
//        Map<String, Integer> merchantAlreadyDistAmount = new HashMap<>(1000); // 记录每个商户已经抽佣过的金额
//        long startId = 0L; // 每批次查询起始id
//        List<PaymentFlowDetailBO> list;
//        do {
//            // 4.1、抓取当日应清分子订单和滞留子订单，每次抓取1000条
//            list = flowDetailService.listSettle(LocalDate.now(), PaymentChannelEnum.UMS.getCode(), startId);
//            List<Map<String, Object>> apprFailAndDistSec = new ArrayList<>();
//            if (!CollectionUtils.isEmpty(list)) {
//                apprFailAndDistSec = settleMatchService.findApprFailAndDistSecFlowDetail(list.stream().map(PaymentFlowDetailBO::getSubOrderFlowId).collect(Collectors.toList()));
//                log.info("查询分账成功但划付失败的流水明细：{}", JsonUtil.toJsonString(apprFailAndDistSec));
//            }
//            for (PaymentFlowDetailBO bo : list) {
//                // 4.2、判断是否有清分规则
//                final SettlementRuleDTO paymentFlowRuleDTO = this.getPaymentFlowRuleDTO(bo, productRuleMap, merchantRuleMap);
//                if (null == paymentFlowRuleDTO) {
//                    lrList.add(bo.getId());
//                    startId = bo.getId();
//                    continue;
//                }
//
//                // 4.3、判断对应商户信息
//                if (null == merchantMap.get(bo.getMerchantCode()) || StringUtils.isEmpty(merchantMap.get(bo.getMerchantCode()).getEnterpriseCode())) {
//                    lmList.add(bo.getId());
//                    startId = bo.getId();
//                    continue;
//                }
//                // 4.4、可正常清分处理逻辑
//                if (merchantFlowDetailIds.get(bo.getMerchantCode()) == null) {
//                    merchantFlowDetailIds.put(bo.getMerchantCode(), new ArrayList<Long>() {{
//                        add(bo.getId());
//                    }});
//                } else {
//                    merchantFlowDetailIds.get(bo.getMerchantCode()).add(bo.getId());
//                }
//                // 先计算平台抽佣金额
//                long distAmount = settlePlatformService.countSubPlatformAmountNew(bo.getOrderAmount(), bo.getProductCount(), paymentFlowRuleDTO);
//                if (distAmount > 0) {
//                    // 判断该流水是否已经抽过佣金
//                    final Optional<Map<String, Object>> optional = apprFailAndDistSec.stream().filter(a -> bo.getSubOrderFlowId().equals(MapUtils.getString(a, "sub_order_flow_id"))).findAny();
//                    if (optional.isPresent()) {
//                        merchantAlreadyDistAmount.merge(bo.getMerchantCode(), (int) distAmount, Integer::sum);
//                        log.warn("子流水已经抽取过佣金，此次不收佣金，sub_flow_id:{}", bo.getSubOrderFlowId());
//                        distAmount = 0;
//                    }
//                }
//                if (null == settleDetailMap.get(bo.getMerchantCode())) {
//                    // 划付内容
//                    SettleDetail settleDetail = new SettleDetail();
//                    settleDetail.setMerchantCode(bo.getMerchantCode());
//                    settleDetail.setApprEnterpriseCode(merchantMap.get(bo.getMerchantCode()).getEnterpriseCode());
//                    settleDetail.setApprId(settleIdHelper(umsAllConfigs.getApprPre()));
//                    settleDetail.setApprCurrencyType("0");
//                    settleDetail.setTargetApprAmount(bo.getOrderAmount().longValue());
//                    settleDetail.setRefundAmount(0L); // 预设退款金额，4.10步骤校正实际金额
//                    settleDetail.setApprAmount(bo.getOrderAmount() - distAmount); // 预设划付金额=支付金额-分账金额，4.10处步骤校正实际金额，需减去实际退款金额且加上返还的抽佣金额
//                    settleDetail.setApprDesc(this.getSettleDesc(bo.getExpectSettleDate()));
//                    settleDetail.setApprStatus(SettleStatusEnum.ING.getCode());
//                    // 分账内容
//                    settleDetail.setDistEnterpriseCode(merchantMap.get(bo.getMerchantCode()).getEnterpriseCode()); // 子商户企业用户号
//                    settleDetail.setDistId(settleIdHelper(umsAllConfigs.getDistPre()));
//                    settleDetail.setDistCurrencyType("0");
//                    settleDetail.setTargetDistAmount(distAmount);
//                    settleDetail.setRefundDistAmount(0L); // 预设退款应返还的分账金额，4.10步骤校正实际金额
//                    settleDetail.setDistAmount(distAmount); // 预设分账金额，4.10步骤校正实际金额，需减去返还的抽佣金额
//                    settleDetail.setDistReceiptName(umsAllConfigs.getReceiptNameTy()); // 腾云收款人名
//                    settleDetail.setDistBankName(umsAllConfigs.getBankNameTy()); // 腾云开户行名称
//                    settleDetail.setDistBankCode(umsAllConfigs.getBankCodeTy()); // 腾云开户行行号
//                    settleDetail.setDistBankAccount(umsAllConfigs.getBankAccountTy()); // 腾云开户行账号
//                    settleDetail.setDistDesc(this.getSettleDesc(bo.getExpectSettleDate()));
//                    settleDetail.setDistStatus(SettleStatusEnum.ING.getCode());
//
//                    settleDetailMap.put(bo.getMerchantCode(), settleDetail); // 收集指令
//                } else {
//                    settleDetailMap.get(bo.getMerchantCode()).setTargetApprAmount(settleDetailMap.get(bo.getMerchantCode()).getTargetApprAmount() + bo.getOrderAmount());
//                    settleDetailMap.get(bo.getMerchantCode()).setApprAmount(settleDetailMap.get(bo.getMerchantCode()).getApprAmount() + bo.getOrderAmount() - distAmount);
//                    settleDetailMap.get(bo.getMerchantCode()).setTargetDistAmount(settleDetailMap.get(bo.getMerchantCode()).getTargetDistAmount() + distAmount);
//                    settleDetailMap.get(bo.getMerchantCode()).setDistAmount(settleDetailMap.get(bo.getMerchantCode()).getDistAmount() + distAmount);
//
//                    settleDetailMap.get(bo.getMerchantCode()).setApprDesc(this.getSettleDesc(bo.getExpectSettleDate()));
//                    settleDetailMap.get(bo.getMerchantCode()).setDistDesc(this.getSettleDesc(bo.getExpectSettleDate()));
//                }
//                // 4.5、可正常清分指令-流水明细映射
//                settleMatches.add(new SettleMatch() {{
//                    setApprId(settleDetailMap.get(bo.getMerchantCode()).getApprId());
//                    setDistId(settleDetailMap.get(bo.getMerchantCode()).getDistId());
//                    setSubOrderId(bo.getSubOrderId());
//                    setSubOrderFlowId(bo.getSubOrderFlowId());
//                }});
//                // 4.6、记录本批次最大id
//                startId = bo.getId();
//            }
//            // 4.7、记录可正常清分指令-流水明细映射记录
//            if (!settleMatches.isEmpty()) {
//                settleMatchService.insertBatch(settleMatches);
//            }
//            // 4.8、更新“缺少清分规则”
//            if (!lrList.isEmpty()) {
//                flowDetailService.updateSettleBatch(lrList, new HashMap<String, Object>() {{
//                    put("settle_status", SETTLE_ERROR);
//                    put("settle_error_desc", LOST_RULE);
//                }});
//            }
//            // 4.9、更新“缺少商户信息或商户企业用户号”
//            if (!lmList.isEmpty()) {
//                flowDetailService.updateSettleBatch(lmList, new HashMap<String, Object>() {{
//                    put("settle_status", SETTLE_ERROR);
//                    put("settle_error_desc", LOST_MERCHANT);
//                }});
//            }
//            settleMatches.clear();
//            lrList.clear();
//            lmList.clear();
//        } while (list.size() > 999); // 只要当前批次数据量为1000，则继续批处理
//        list.clear();
//        list = null;
//        settleMatches = null;
//        lrList = null;
//        lmList = null;
//        /*
//         * 4.10 处理退款轧差、退款返佣
//         * 加入退款轧差逻辑  2021-02-02
//         * 加入退款返佣逻辑  2021-02-02
//         */
//        calRefundAndDist(merchantMap.keySet(), settleDetailMap, merchantFlowDetailIds, merchantAlreadyDistAmount);
//
//        merchantFlowDetailIds.clear();
//        merchantFlowDetailIds = null;
//    }
//
//    /**
//     * 获取清分附言
//     *
//     * @param expectSettleDate 流水核销时间
//     * @return
//     */
//    private String getSettleDesc(LocalDate expectSettleDate) {
//        if (null == expectSettleDate) {
//            return "腾云交易清算";
//        }
//        return "腾云" + expectSettleDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + "交易清算";
//    }
//
//    /**
//     * 取支付流水对应的清分规则
//     *
//     * @param bo              支付流水
//     * @param productRuleMap  商品清分规则集合
//     * @param merchantRuleMap 商户清分规则集合
//     * @return 流水对应的清分规则
//     */
//    private SettlementRuleDTO getPaymentFlowRuleDTO(PaymentFlowDetailBO bo, Map<String, SettlementRuleDTO> productRuleMap,
//                                                    Map<String, SettlementRuleDTO> merchantRuleMap) {
//        if (null != productRuleMap && null != productRuleMap.get(StringUtils.join(bo.getMerchantCode(), "-", bo.getProductId()))) {
//            log.info("取支付流水清分规则，使用商品清分规则，key：{},subOrderFlowId:{}", StringUtils.join(bo.getMerchantCode(), "-", bo.getProductId()), bo.getSubOrderFlowId());
//            return productRuleMap.get(StringUtils.join(bo.getMerchantCode(), "-", bo.getProductId()));
//        }
//        if (null != merchantRuleMap && null != merchantRuleMap.get(bo.getMerchantCode())) {
//            log.info("取支付流水清分规则，使用商户清分规则，merchantCode：{},subOrderFlowId:{}", bo.getMerchantCode(), bo.getSubOrderFlowId());
//            return merchantRuleMap.get(bo.getMerchantCode());
//        }
//        log.warn("取支付流水清分规则，无清分规则，merchantCode：{},productId：{},subOrderFlowId:{}", bo.getMerchantCode(), bo.getProductId(), bo.getSubOrderFlowId());
//        return null;
//    }
//
//
//    /**
//     * 取退款流水对应的清分规则
//     *
//     * @param bo              退款流水
//     * @param productRuleMap  商品清分规则集合
//     * @param merchantRuleMap 商户清分规则集合
//     * @return 流水对应的清分规则
//     */
//    private SettlementRuleDTO getRefundFlowRuleDTO(RefundSettleBO bo, Map<String, SettlementRuleDTO> productRuleMap,
//                                                   Map<String, SettlementRuleDTO> merchantRuleMap) {
//        if (null != productRuleMap && null != productRuleMap.get(StringUtils.join(bo.getMerchantCode(), "-", bo.getProductId()))) {
//            log.info("取退款流水清分规则，使用商品清分规则，key：{},subOrderFlowId:{}", StringUtils.join(bo.getMerchantCode(), "-", bo.getProductId()), bo.getSubFlowId());
//            return productRuleMap.get(StringUtils.join(bo.getMerchantCode(), "-", bo.getProductId()));
//        }
//        if (null != merchantRuleMap && null != merchantRuleMap.get(bo.getMerchantCode())) {
//            log.info("取退款流水清分规则，使用商户清分规则，merchantCode：{},subOrderFlowId:{}", bo.getMerchantCode(), bo.getSubFlowId());
//            return merchantRuleMap.get(bo.getMerchantCode());
//        }
//        log.warn("取退款流水清分规则，无清分规则，merchantCode：{},productId：{},subOrderFlowId:{}", bo.getMerchantCode(), bo.getProductId(), bo.getSubFlowId());
//        return null;
//    }
//
//
//    /**
//     * 处理轧差、退款返佣
//     *
//     * @param merchantCodes             {@link Collection<String>} 交易中心商户编码列表：merchantCodes
//     * @param settleDetailMap           {@link Map} 清分文件指令明细集合：key=merchantCode, value=SettleDetail
//     * @param merchantFlowDetailIds     {@link Map} 商户可正常清分的支付子流水id列表集合：key=merchantCode, value=支付子流水id列表
//     * @param merchantAlreadyDistAmount {@link Map} 每个商户已经抽佣过的金额：key=merchantCode, value=已经抽抽佣过的金额
//     */
//    private void calRefundAndDist(Collection<String> merchantCodes, Map<String, SettleDetail> settleDetailMap, Map<String,
//            List<Long>> merchantFlowDetailIds, Map<String, Integer> merchantAlreadyDistAmount) {
//        List<RefundSettleBO> rList = new ArrayList<>(1000); // 退款流水
//        List<Long> allFlowDetailIds = new ArrayList<>();
//        merchantFlowDetailIds.values().forEach(allFlowDetailIds::addAll); // 收集所有清分支付流水id
//        List<List<Long>> allFlowDetailIdSplits = CommonUtil.splitList(allFlowDetailIds, 2000); // 每2000为一次查询数量
//        for (List<Long> flowDetailIds : allFlowDetailIdSplits) {
//            if (CollectionUtils.isEmpty(flowDetailIds)) {
//                log.info("处理轧差、退款返佣，支付流水为空。");
//                continue;
//            }
//            rList.addAll(refundService.listApprRefund(flowDetailIds)); // 查询当日清分支付流水中退款成功的退款流水
//        }
//        if (!CollectionUtils.isEmpty(merchantCodes)) {
//            rList.addAll(refundService.listSettleRefund(merchantCodes)); // 查询核销后退款的退款流水
//        }
//        if (rList.isEmpty()) {
//            log.info("处理轧差、退款返佣，无待处理的退款流水.设置支付流水为清分中");
//            for (Iterator<Map.Entry<String, SettleDetail>> it = settleDetailMap.entrySet().iterator(); it.hasNext(); ) {
//                Map.Entry<String, SettleDetail> item = it.next();
//                if (!CollectionUtils.isEmpty(merchantFlowDetailIds.get(item.getValue().getMerchantCode()))) {
//                    flowDetailService.updateSettleBatch(merchantFlowDetailIds.get(item.getValue().getMerchantCode()), new HashMap<String, Object>() {{
//                        put("settle_status", SETTLE_ING);
//                        put("settle_error_desc", null);
//                    }});
//
//                    // 判断该商户，该批次支付流水里面是否有已经抽过佣金的，如果有则需要扣除掉
//                    // 校正实际抽佣金额
//                    item.getValue().setDistAmount(item.getValue().getDistAmount() - item.getValue().getRefundDistAmount());
//                    // 最终划付金额计算，支付抽佣、退款抽佣冲正
//                    // 已经抽佣的金额
//                    int alreadyDistAmount = ((null == merchantAlreadyDistAmount.get(item.getValue().getMerchantCode()) ? 0 : merchantAlreadyDistAmount.get(item.getValue().getMerchantCode())));
//                    log.info("商户{},已经抽佣成功的金额:{}，支付已抽佣金额:{}", item.getValue().getMerchantCode(), alreadyDistAmount, merchantAlreadyDistAmount.get(item.getValue().getMerchantCode()));
//                    long cnt = item.getValue().getApprAmount() - alreadyDistAmount;
//                    log.info("退款返佣：{}，原划付金额:{},返佣金额：{},实际已经抽佣过的金额：{},最终划付金额：{}", item.getValue().getApprAmount(),
//                            item.getValue().getApprId(), item.getValue().getRefundDistAmount(), alreadyDistAmount, cnt);
//
//                    // 2）“划付金额”、“分账金额”两者某一项金额计算为负，则将该商户的支付流水、退款流水的清分状态改为ERROR，且该商户不参与当日清分处理
//                    if (cnt < 0 || item.getValue().getDistAmount() < 0) {
//                        // 移除清分指令-流水明细映射
//                        settleMatchService.remove("appr_id", item.getValue().getApprId());
//                        // 移除该商户清分指令
//                        it.remove();
//                        if (!merchantFlowDetailIds.get(item.getValue().getMerchantCode()).isEmpty()) {
//                            // 更新支付流水清分状态
//                            flowDetailService.updateSettleBatch(merchantFlowDetailIds.get(item.getValue().getMerchantCode()), new HashMap<String, Object>() {{
//                                put("settle_status", SETTLE_ERROR);
//                                if (cnt < 0) {
//                                    put("settle_error_desc", LESS_APPR_AMOUNT);
//                                } else {
//                                    put("settle_error_desc", LESS_DIST_AMOUNT);
//                                }
//                            }});
//                        }
//                        continue;
//                    }
//                    item.getValue().setApprAmount(cnt);
//                    // 3）若刚好为0，直接记录清分状态为成功(后续的清分指令文件将不包含该条)
//                    if (cnt == 0) {
//                        if (!merchantFlowDetailIds.get(item.getValue().getMerchantCode()).isEmpty()) {
//                            flowDetailService.updateSettleBatch(merchantFlowDetailIds.get(item.getValue().getMerchantCode()), new HashMap<String, Object>() {{
//                                put("settle_status", SETTLE_SUCCESS);
//                                put("settle_error_desc", "轧差刚好为0");
//                            }});
//                        }
//                        continue;
//                    }
//
//                }
//            }
//            return;
//        }
//        log.info("清分任务，应清分退款流水：{}笔", rList.size());
//        //Set<String> productIds = new HashSet<>();
//        Set<String> allMerchantCodes = new HashSet<>();
//        List<List<RefundSettleBO>> rListSplits = CommonUtil.splitList(rList, 2000);
//
//        HashSet<Map<String, String>> products = new HashSet<>();
//
//        for (List<RefundSettleBO> rListSplit : rListSplits) {
//            Set<Long> fdids = rListSplit.stream().map(RefundSettleBO::getFdid).collect(Collectors.toSet());
//            List<PaymentFlowDetail> details = flowDetailService.selectList(new QueryWrapper<PaymentFlowDetail>() {{
//                in("id", fdids);
//            }});
//            //productIds.addAll(details.stream().map(PaymentFlowDetail::getProductId).collect(Collectors.toSet()));
//            for (PaymentFlowDetail detail : details) {
//                Map<String, String> p = new HashMap<>();
//                p.put("merchant_code", detail.getMerchantCode());
//                p.put("product_code", detail.getProductId());
//                products.add(p);
//            }
//            allMerchantCodes.addAll(details.stream().map(PaymentFlowDetail::getMerchantCode).collect(Collectors.toSet()));
//        }
//        // 退款流水,商品清分规则
//
//        Map<String, SettlementRuleDTO> productRuleMap = settlePlatformService.getSettlementRuleMap(products);
//        // 退款流水,商户清分规则
//        Map<String, SettlementRuleDTO> merchantRuleMap = settlePlatformService.getSettlementRuleMapByMerchantCods(allMerchantCodes);
//        products.clear();
//        products = null;
//        allMerchantCodes.clear();
//        allMerchantCodes = null;
//        rListSplits.clear();
//        rListSplits = null;
//
//        // 4.11.1 以商户维度聚合应返还分账金额
//        Map<Long, Integer> refundRuleLostMap = new HashMap<>(100); // 缺少清分规则退款流水明细id
//        Map<String, Integer> refundSettleDistMap = new HashMap<>(1000); // 商户返还分账金额：key=merchantCode, value=商户当日返还分账金额
//        Map<String, Integer> todayBackPlatformFixRefundDistSubOrder = new HashMap<>();// 今天执行退还固定金额抽佣的子订单，防止当天重复返佣
//        // 统计子订单已退款金额，用于固定金额返还佣金（整个子订单退完时，返回支付已抽的佣金）
//        List<StatisticsSubOrderRefundBo> statisticsSubOrderRefundBos = refundFlowDetailService.statisticsSubOrderRefund(rList.stream().map(RefundSettleBO::getSubOrderId).collect(Collectors.toList()));
//        //TODO 查询已退还抽佣金成功的退款单
//        final List<Map<String, Object>> backedDistRefunds = settleMatchRefundService.findApprFailAndDistSecFlowDetail(rList.stream().map(RefundSettleBO::getFlowId).collect(Collectors.toList()));
//        // 已经退还过佣金商户金额
//        Map<String, Integer> alreadyDistMap = new HashMap<>(1000); // 商户返还分账金额：key=merchantCode, value=商户当日返还分账金额
//        for (RefundSettleBO refundSettleBO : rList) {
//            final SettlementRuleDTO refundFlowRuleDTO = this.getRefundFlowRuleDTO(refundSettleBO, productRuleMap, merchantRuleMap);
//            if (null != refundFlowRuleDTO) {
//                int backDistAmount = 0;
//                switch (refundFlowRuleDTO.getClearingRule()) {
//                    case SettlementRuleDTO.CLEARING_RULE_RATE: // 百分比
//                        int backDist = settlePlatformService.countSubPlatformAmountNew((refundSettleBO.getAmount() + refundSettleBO.getRefundPlatformDiscount()), 1, refundFlowRuleDTO);
//                        log.info("退款百分比抽佣：refund_flow_id:{},refund_amount:{}，退款返佣金：{}", refundSettleBO.getFlowId(), refundSettleBO.getAmount() + refundSettleBO.getRefundPlatformDiscount(), backDist);
//                        backDistAmount = backDist;
//                        refundSettleDistMap.merge(refundSettleBO.getMerchantCode(), backDist, Integer::sum);
//                        break;
//                    case SettlementRuleDTO.CLEARING_RULE_NUM_P: // 平台固定金额
//                        // 退还商户固定金额抽佣
//                        AtomicInteger backRefundDist = new AtomicInteger();
//                        if (!CollectionUtils.isEmpty(statisticsSubOrderRefundBos) && !todayBackPlatformFixRefundDistSubOrder.containsKey(refundSettleBO.getSubOrderId())) {
//                            statisticsSubOrderRefundBos.stream().filter(s -> s.getSubOrderId().equals(refundSettleBO.getSubOrderId()) && s.getRefundedAmount().equals(s.getOrderAmount())).findFirst().ifPresent(p -> {
//                                backRefundDist.set(refundFlowRuleDTO.getPlatformFix() * refundSettleBO.getProductCount());
//                                log.info("退款退还平台固定抽佣，refund_flow_id:{},sub_order_id:{},金额：{}", refundSettleBO.getFlowId(), refundSettleBO.getSubOrderId(), backRefundDist.get());
//                                todayBackPlatformFixRefundDistSubOrder.put(refundSettleBO.getSubOrderId(), backRefundDist.get());
//                            });
//                        }
//                        backDistAmount = backRefundDist.get();
//                        refundSettleDistMap.merge(refundSettleBO.getMerchantCode(), backRefundDist.get(), Integer::sum);
//                        break;
//                    case SettlementRuleDTO.CLEARING_RULE_NUM_M: // 商户固定金额
//                        AtomicInteger backRefundDist2 = new AtomicInteger();
//                        if (!CollectionUtils.isEmpty(statisticsSubOrderRefundBos) && !todayBackPlatformFixRefundDistSubOrder.containsKey(refundSettleBO.getSubOrderId())) {
//                            statisticsSubOrderRefundBos.stream().filter(s -> s.getSubOrderId().equals(refundSettleBO.getSubOrderId()) && s.getRefundedAmount().equals(s.getOrderAmount())).findFirst().ifPresent(p -> {
//                                backRefundDist2.set((refundSettleBO.getOrderAmount() - refundFlowRuleDTO.getMerchantFix() * refundSettleBO.getProductCount()));
//                                log.info("退款退还商户固定金额，refund_flow_id:{},sub_order_id:{},金额：{}", refundSettleBO.getFlowId(), refundSettleBO.getSubOrderId(), backRefundDist2.get());
//                                todayBackPlatformFixRefundDistSubOrder.put(refundSettleBO.getSubOrderId(), backRefundDist2.get());
//                            });
//                        }
//                        backDistAmount = backRefundDist2.get();
//                        refundSettleDistMap.merge(refundSettleBO.getMerchantCode(), backRefundDist2.get(), Integer::sum);
//                        break;
//                }
//                if (!CollectionUtils.isEmpty(backedDistRefunds)) {
//                    final Optional<Map<String, Object>> any = backedDistRefunds.stream().filter(b -> refundSettleBO.getFlowId().equals(MapUtils.getString(b, "refund_flow_id"))
//                            && refundSettleBO.getSubOrderId().equals(MapUtils.getString(b, "sub_order_id"))).findAny();
//                    if (any.isPresent()) {
//                        log.warn("已退还过佣金:{}，不再执行退佣金。refund_flow_id:{},sub_order_id:{}", backDistAmount, refundSettleBO.getFlowId(), refundSettleBO.getSubOrderId());
//                        alreadyDistMap.merge(refundSettleBO.getMerchantCode(), backDistAmount, Integer::sum);
//                    }
//                }
//            } else {
//                refundRuleLostMap.put(refundSettleBO.getId(), 1);
//            }
//        }
//        // 4.11.2 以商户为单位聚合退款额、退款明细id、对应退款流水号-支付子订单号
//        Map<String, Object[]> rdStMap = new HashMap<>(1000);
//        for (Iterator<RefundSettleBO> iterator = rList.iterator(); iterator.hasNext(); ) {
//            RefundSettleBO refundSettleBO = iterator.next();
//            if (null != refundRuleLostMap.get(refundSettleBO.getId())) { // 若退款流水属于缺少清分规则，不参与清分，记录清分失败
//                iterator.remove();
//                continue;
//            }
//            if (rdStMap.get(refundSettleBO.getMerchantCode()) == null) {
//                rdStMap.put(refundSettleBO.getMerchantCode(), new Object[]{
//                        refundSettleBO.getAmount() + refundSettleBO.getRefundPlatformDiscount(), // 退款额
//                        new ArrayList<Long>() {{
//                            add(refundSettleBO.getId());
//                        }}, // 退款明细id
//                        new ArrayList<String[]>() {{
//                            add(new String[]{refundSettleBO.getFlowId(), refundSettleBO.getSubOrderId()});
//                        }} // 退款流水号-支付子订单号
//                });
//            } else {
//                rdStMap.get(refundSettleBO.getMerchantCode())[0] = (int) rdStMap.get(refundSettleBO.getMerchantCode())[0] + refundSettleBO.getAmount() + refundSettleBO.getRefundPlatformDiscount();
//                ((ArrayList<Long>) rdStMap.get(refundSettleBO.getMerchantCode())[1]).add(refundSettleBO.getId());
//                ((ArrayList<String[]>) rdStMap.get(refundSettleBO.getMerchantCode())[2]).add(new String[]{refundSettleBO.getFlowId(), refundSettleBO.getSubOrderId()});
//            }
//        }
//        // 记录缺少清分规则的退款流水
//        if (!refundRuleLostMap.isEmpty()) {
//            refundFlowDetailService.updateSettleBatch(refundRuleLostMap.keySet(), new HashMap<String, Object>() {{
//                put("settle_status", SETTLE_ERROR);
//                put("settle_error_desc", LOST_RULE);
//            }});
//        }
//        // 集合、列表引用清除
//        rList.clear();
//        rList = null;
//        productRuleMap.clear();
//        productRuleMap = null;
//        merchantRuleMap.clear();
//        merchantRuleMap = null;
//        allFlowDetailIds.clear();
//        allFlowDetailIds = null;
//        allFlowDetailIdSplits.clear();
//        allFlowDetailIdSplits = null;
//        refundRuleLostMap.clear();
//        refundRuleLostMap = null;
//        // 4.11.3 清分明细加入退款因素、返佣因素再次计算
//        for (Iterator<Map.Entry<String, SettleDetail>> it = settleDetailMap.entrySet().iterator(); it.hasNext(); ) {
//            Map.Entry<String, SettleDetail> item = it.next();
//            // 1）若无退款流水，更新对应支付流水的清分状态为清分中
//            if (null == rdStMap.get(item.getValue().getMerchantCode())) {
//                if (!merchantFlowDetailIds.get(item.getValue().getMerchantCode()).isEmpty()) {
//                    flowDetailService.updateSettleBatch(merchantFlowDetailIds.get(item.getValue().getMerchantCode()), new HashMap<String, Object>() {{
//                        put("settle_status", SETTLE_ING);
//                        put("settle_error_desc", null);
//                    }});
//                    log.info("处理轧差、退款返佣，商户{}无待处理的退款流水.设置支付流水为清分中，处理重复抽佣。", item.getValue().getMerchantCode());
//
//                    // 判断该商户，该批次支付流水里面是否有已经抽过佣金的，如果有则需要扣除掉
//                    // 校正实际抽佣金额
//                    item.getValue().setDistAmount(item.getValue().getDistAmount() - item.getValue().getRefundDistAmount());
//                    // 最终划付金额计算，支付抽佣、退款抽佣冲正
//                    // 已经抽佣的金额
//                    int alreadyDistAmount = ((null == merchantAlreadyDistAmount.get(item.getValue().getMerchantCode()) ? 0 : merchantAlreadyDistAmount.get(item.getValue().getMerchantCode())));
//                    log.info("商户：{},已经抽佣成功的金额:{}，支付已抽佣金额:{}", item.getValue().getMerchantCode(), alreadyDistAmount, merchantAlreadyDistAmount.get(item.getValue().getMerchantCode()));
//                    long cnt = item.getValue().getApprAmount() + item.getValue().getRefundDistAmount() - alreadyDistAmount;
//                    log.info("退款返佣：{}，原划付金额:{}，返佣金额：{},实际已经抽佣过的金额：{},最终划付金额：{}", item.getValue().getApprAmount(),
//                            item.getValue().getApprId(), item.getValue().getRefundDistAmount(), alreadyDistAmount, cnt);
//
//                    // 2）“划付金额”、“分账金额”两者某一项金额计算为负，则将该商户的支付流水、退款流水的清分状态改为ERROR，且该商户不参与当日清分处理
//                    if (cnt < 0 || item.getValue().getDistAmount() < 0) {
//                        // 移除清分指令-流水明细映射
//                        settleMatchService.remove("appr_id", item.getValue().getApprId());
//                        // 移除该商户清分指令
//                        it.remove();
//                        if (!merchantFlowDetailIds.get(item.getValue().getMerchantCode()).isEmpty()) {
//                            // 更新支付流水清分状态
//                            flowDetailService.updateSettleBatch(merchantFlowDetailIds.get(item.getValue().getMerchantCode()), new HashMap<String, Object>() {{
//                                put("settle_status", SETTLE_ERROR);
//                                if (cnt < 0) {
//                                    put("settle_error_desc", LESS_APPR_AMOUNT);
//                                } else {
//                                    put("settle_error_desc", LESS_DIST_AMOUNT);
//                                }
//                            }});
//                        }
//                        continue;
//                    }
//                    item.getValue().setApprAmount(cnt);
//                    // 3）若刚好为0，直接记录清分状态为成功(后续的清分指令文件将不包含该条)
//                    if (cnt == 0) {
//                        if (!merchantFlowDetailIds.get(item.getValue().getMerchantCode()).isEmpty()) {
//                            flowDetailService.updateSettleBatch(merchantFlowDetailIds.get(item.getValue().getMerchantCode()), new HashMap<String, Object>() {{
//                                put("settle_status", SETTLE_SUCCESS);
//                                put("settle_error_desc", "轧差刚好为0");
//                            }});
//                        }
//                        continue;
//                    }
//                }
//                continue;
//            }
//            // 校正实际退款额
//            item.getValue().setRefundAmount((long) ((int) rdStMap.get(item.getValue().getMerchantCode())[0]));
//            // 校正实际返佣额
//            // 已经退还过的抽佣金额
//            int alreadyBackDistAmount = null == alreadyDistMap.get(item.getValue().getMerchantCode()) ? 0 : alreadyDistMap.get(item.getValue().getMerchantCode());
//            if (null == refundSettleDistMap.get(item.getValue().getMerchantCode())) {
//                item.getValue().setRefundDistAmount(0L);
//            } else {
//                if (alreadyBackDistAmount > 0) {
//                    // 减掉已经返还过的佣金
//                    item.getValue().setRefundDistAmount(refundSettleDistMap.get(item.getValue().getMerchantCode()).longValue() - alreadyBackDistAmount);
//                } else {
//                    item.getValue().setRefundDistAmount(refundSettleDistMap.get(item.getValue().getMerchantCode()).longValue());
//                }
//            }
//            // 校正实际抽佣金额
//            item.getValue().setDistAmount(item.getValue().getDistAmount() - item.getValue().getRefundDistAmount());
//            // 最终划付金额计算，支付抽佣、退款抽佣冲正
//            // 已经抽佣的金额
//            int alreadyDistAmount = ((null == merchantAlreadyDistAmount.get(item.getValue().getMerchantCode()) ? 0 : merchantAlreadyDistAmount.get(item.getValue().getMerchantCode())) - alreadyBackDistAmount);
//            log.info("商户{},已经抽佣成功的金额:{}，支付已抽佣金额:{}", item.getValue().getMerchantCode(), alreadyDistAmount, merchantAlreadyDistAmount.get(item.getValue().getMerchantCode()));
//            long cnt = item.getValue().getApprAmount() - ((int) rdStMap.get(item.getValue().getMerchantCode())[0]) + item.getValue().getRefundDistAmount() - alreadyDistAmount;
//            log.info("商户{},退款返佣：{}，原划付金额:{}，退款金额:{}，返佣金额：{},实际已经抽佣过的金额：{},最终划付金额：{}，最终分账金额：{}", item.getValue().getMerchantCode(), item.getValue().getApprAmount(),
//                    item.getValue().getApprId(), rdStMap.get(item.getValue().getMerchantCode())[0], item.getValue().getRefundDistAmount(), alreadyBackDistAmount, cnt, item.getValue().getDistAmount());
//            // 2）“划付金额”、“分账金额”两者某一项金额计算为负，则将该商户的支付流水、退款流水的清分状态改为ERROR，且该商户不参与当日清分处理
//            log.info("商户{}，支付流水{}，退款明细：{}", item.getValue().getMerchantCode(), JsonUtil.toJsonString(merchantFlowDetailIds.get(item.getValue().getMerchantCode())),
//                    JsonUtil.toJsonString(rdStMap.get(item.getValue().getMerchantCode())[1]));
//            if (cnt < 0 || item.getValue().getDistAmount() < 0) {
//                // 移除清分指令-流水明细映射
//                settleMatchService.remove("appr_id", item.getValue().getApprId());
//                log.warn("商户{}划付活着分账金额小于0，不清分", item.getValue().getMerchantCode());
//                // 移除该商户清分指令
//                it.remove();
//                if (!merchantFlowDetailIds.get(item.getValue().getMerchantCode()).isEmpty()) {
//                    log.warn("商户{}划付活着分账金额小于0，不清分，标识支付流水为清分失败", item.getValue().getMerchantCode());
//                    // 更新支付流水清分状态
//                    flowDetailService.updateSettleBatch(merchantFlowDetailIds.get(item.getValue().getMerchantCode()), new HashMap<String, Object>() {{
//                        put("settle_status", SETTLE_ERROR);
//                        if (cnt < 0) {
//                            put("settle_error_desc", LESS_APPR_AMOUNT);
//                        } else {
//                            put("settle_error_desc", LESS_DIST_AMOUNT);
//                        }
//                    }});
//                }
//                if (!((ArrayList<Long>) rdStMap.get(item.getValue().getMerchantCode())[1]).isEmpty()) {
//                    // 更新退款流水清分状态
//                    refundFlowDetailService.updateSettleBatch((ArrayList<Long>) rdStMap.get(item.getValue().getMerchantCode())[1], new HashMap<String, Object>() {{
//                        put("settle_status", SETTLE_ERROR);
//                        if (cnt < 0) {
//                            put("settle_error_desc", LESS_APPR_AMOUNT);
//                        } else {
//                            put("settle_error_desc", LESS_DIST_AMOUNT);
//                        }
//                    }});
//                }
//                continue;
//            }
//            item.getValue().setApprAmount(cnt);
//            log.info("商户:{},汇总：{}", item.getKey(), JsonUtil.toJsonString(item.getValue()));
//            // 记录清分指令-退款流水、支付子订单号映射关系
//            if (!((ArrayList<String[]>) rdStMap.get(item.getValue().getMerchantCode())[2]).isEmpty()) {
//                List<SettleMatchRefund> smrList = ((ArrayList<String[]>) rdStMap.get(item.getValue().getMerchantCode())[2]).stream().map(arr -> new SettleMatchRefund() {{
//                    setApprId(item.getValue().getApprId());
//                    setDistId(item.getValue().getDistId());
//                    setRefundFlowId(arr[0]);
//                    setSubOrderId(arr[1]);
//                }}).collect(Collectors.toList());
//                settleMatchRefundService.saveBatch(smrList);
//            }
//            // 3）若刚好为0，直接记录清分状态为成功(后续的清分指令文件将不包含该条)
//            if (cnt == 0) {
//                if (!merchantFlowDetailIds.get(item.getValue().getMerchantCode()).isEmpty()) {
//                    flowDetailService.updateSettleBatch(merchantFlowDetailIds.get(item.getValue().getMerchantCode()), new HashMap<String, Object>() {{
//                        put("settle_status", SETTLE_SUCCESS);
//                        put("settle_error_desc", "轧差刚好为0");
//                    }});
//                }
//                if (!((ArrayList<Long>) rdStMap.get(item.getValue().getMerchantCode())[1]).isEmpty()) {
//                    refundFlowDetailService.updateSettleBatch((ArrayList<Long>) rdStMap.get(item.getValue().getMerchantCode())[1], new HashMap<String, Object>() {{
//                        put("settle_status", SETTLE_SUCCESS);
//                        put("settle_error_desc", "轧差刚好为0");
//                    }});
//                }
//                continue;
//            }
//            // 4）若为正，记录清分状态为清分中
//            if (!merchantFlowDetailIds.get(item.getValue().getMerchantCode()).isEmpty()) {
//                flowDetailService.updateSettleBatch(merchantFlowDetailIds.get(item.getValue().getMerchantCode()), new HashMap<String, Object>() {{
//                    put("settle_status", SETTLE_ING);
//                    put("settle_error_desc", null);
//                }});
//            }
//            if (!((ArrayList<Long>) rdStMap.get(item.getValue().getMerchantCode())[1]).isEmpty()) {
//                refundFlowDetailService.updateSettleBatch((ArrayList<Long>) rdStMap.get(item.getValue().getMerchantCode())[1], new HashMap<String, Object>() {{
//                    put("settle_status", SETTLE_ING);
//                    put("settle_error_desc", null);
//                }});
//            }
//        }
//        // 集合、列表引用清除
//        refundSettleDistMap.clear();
//        refundSettleDistMap = null;
//        rdStMap.clear();
//        rdStMap = null;
//    }
//
//    /**
//     * 清分文件处理
//     * - 生成划付文件和分账文件
//     * - 补充settleDetailMap中划付-文件名、分账-文件名
//     * - 生成清分文件数据库记录
//     * - 数据库记录清分指令明细、清分文件记录
//     *
//     * @param settleDetailMap {@link Map} 清分文件指令明细
//     * @param apprFiles       {@link List} 划付文件
//     * @param distFiles       {@link List} 分账文件
//     */
//    private void handleSettleFile(Map<String, SettleDetail> settleDetailMap,
//                                  List<File> apprFiles,
//                                  List<File> distFiles) {
//        int first = 1;
//        // 数据切割，每个文件最多10000条数据量，此处设置每个文件最多（FILE_MAX+1）条
//        for (Map<String, SettleDetail> map : splitMap(settleDetailMap, FILE_MAX)) {
//            // 5.1、生成划付文件名和分账文件名
//            String apprFileName = umsAllConfigs.getApprPre() + umsAllConfigs.getGroupCode() + "_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + ".txt";
//            String distFileName = umsAllConfigs.getDistPre() + apprFileName.substring(umsAllConfigs.getApprPre().length());
//            // 5.2、生成清分指令内容行
//            List<String> apprLines = new ArrayList<>(); // 划付指令内容行
//            apprLines.add(""); // 首行先占位，给汇总行预留
//            List<String> distLines = new ArrayList<>();// 分账指令内容行
//            distLines.add(""); // 首行先占位，给汇总行预留
//            long apprTotalAmount = 0; // 划付-总金额
//            long distTotalAmount = 0; // 分账-总金额
//            // 如果划付金额为0，则直接设置状态划付状态为成功，若分账金额小于0，直接设置为失败，两种情况均不生成划付指令；分账逻辑同理
//            for (SettleDetail settleDetail : map.values()) {
//                settleDetail.setApprFileName(apprFileName); // 补充划付-文件名
//                settleDetail.setDistFileName(distFileName); // 补充分账-文件名
//                // 划付
//                if (settleDetail.getApprAmount() == 0) {
//                    settleDetail.setApprStatus(SettleStatusEnum.SUCCESS.getCode());
//                    settleDetail.setApprDesc("划付金额为0，无需执行划付");
//                } else if (settleDetail.getApprAmount() < 0) {
//                    settleDetail.setApprStatus(SettleStatusEnum.FAIL.getCode());
//                    settleDetail.setApprDesc("划付金额小于0，清分规则异常，不执行划付");
//                } else {
//                    // 划付明细行：指令id|企业用户号|划付金额类型|划付金额|划付附言
//                    apprLines.add(settleDetail.getApprId() + "|" + settleDetail.getApprEnterpriseCode() + "|" +
//                            settleDetail.getApprCurrencyType() + "|" + settleDetail.getApprAmount() + "|" +
//                            settleDetail.getApprDesc());
//                    apprTotalAmount += settleDetail.getApprAmount();
//                }
//                // 分账
//                if (settleDetail.getDistAmount() == 0) {
//                    settleDetail.setDistStatus(SettleStatusEnum.SUCCESS.getCode());
//                    settleDetail.setDistDesc("分账金额为0，无需执行分账");
//                } else if (settleDetail.getDistAmount() < 0) {
//                    settleDetail.setDistStatus(SettleStatusEnum.FAIL.getCode());
//                    settleDetail.setDistDesc("分账金额小于0，清分规则异常，不执行分账");
//                } else {
//                    // 分账明细行：指令id|企业用户号|分账金额类型|分账金额|收款人名称|开户行名称|开户行行号|开户行账号|分账附言
//                    distLines.add(settleDetail.getDistId() + "|" + settleDetail.getDistEnterpriseCode() + "|" +
//                            settleDetail.getDistCurrencyType() + "|" + settleDetail.getDistAmount() + "|" +
//                            settleDetail.getDistReceiptName() + "|" + settleDetail.getDistBankName() + "|" +
//                            settleDetail.getDistBankCode() + "|" + settleDetail.getDistBankAccount() + "|" +
//                            settleDetail.getDistDesc());
//                    distTotalAmount += settleDetail.getDistAmount();
//                }
//            }
//
//            // 判断划付成功且分账失败的记录，再次尝试抽佣
//            final List<SettleDistErrorBO> settleDistErrorBOS = settleDistErrorService.queryDateSettle();
//            final List<SettleDistError> settleDistErrors = new ArrayList<>();
//            if (!CollectionUtils.isEmpty(settleDistErrorBOS)) {
//                log.info("存在需要重新抽佣的记录:{}", JsonUtil.toJsonString(settleDistErrorBOS));
//                for (SettleDistErrorBO sd : settleDistErrorBOS) {
//                    String distId = settleIdHelper(umsAllConfigs.getDistPre());
//                    distLines.add(distId + "|" + sd.getDistEnterpriseCode() + "|" +
//                            sd.getDistCurrencyType() + "|" + sd.getDistAmount() + "|" +
//                            sd.getDistReceiptName() + "|" + sd.getDistBankName() + "|" +
//                            sd.getDistBankCode() + "|" + sd.getDistBankAccount() + "|" +
//                            "重新处理-" + sd.getDistDesc());
//                    distTotalAmount += sd.getDistAmount();
//                    SettleDistError settleDistError = new SettleDistError();
//                    settleDistError.setSourceDistId(sd.getDistId());
//                    settleDistError.setBatchDistId(distId);
//                    settleDistError.setDistAmount(sd.getDistAmount().intValue());
//                    settleDistError.setDistStatus(SettleStatusEnum.ING.getCode());
//                    settleDistError.setDistDesc("重新处理-" + sd.getDistDesc());
//                    settleDistError.setCreateTime(LocalDateTime.now());
//                    settleDistError.setDistAmountSc(0);
//                    settleDistError.setDistFileName(distFileName); //分账-名称
//                    settleDistErrors.add(settleDistError);
//
//                }
//                log.info("重新抽取佣的明细记录：{}", JsonUtil.toJsonString(settleDistErrors));
//            }
//            // 划付汇总行：集团编号|总笔数
//            apprLines.set(0, umsAllConfigs.getGroupCode() + "|" + (apprLines.size() - 1));
//            // 分账汇总行：集团编号|总笔数
//            distLines.set(0, umsAllConfigs.getGroupCode() + "|" + (distLines.size() - 1));
//            log.info("生成划付文件：{}",JsonUtil.toJsonString(apprLines));
//            log.info("生成分账文件：{}",JsonUtil.toJsonString(distLines));
//            // 5.3、生成上传文件
//            apprFiles.add(TxtUtil.createTxtFile(apprFileName, apprLines, "utf-8"));
//            distFiles.add(TxtUtil.createTxtFile(distFileName, distLines, "utf-8"));
//            // 5.4、生成清分文件数据库记录
//            SettleFile settleFile = new SettleFile();
//            settleFile.setClearDate(LocalDate.now());
//            // 划付内容
//            settleFile.setGroupCode(umsAllConfigs.getGroupCode()); // 商户集团编号
//            settleFile.setChannel(PaymentChannelEnum.UMS.getCode()); // 渠道：cmb=计平；ums=银联商务
//            settleFile.setApprFileName(apprFileName); // 划付-文件名
//            settleFile.setApprTotalNum(apprLines.size() - 1); // 划付-总笔数
//            settleFile.setApprTotalAmount(apprTotalAmount); // 划付-总金额
//            // 分账内容
//            settleFile.setDistFileName(distFileName); // 分账-文件名
//            settleFile.setDistTotalNum(distLines.size() - 1); // 分账-总笔数
//            settleFile.setDistTotalAmount(distTotalAmount); // 分账-总金额
//            // 5.5、数据库记录
//            log.info("保存清分明细：{}", JsonUtil.toJsonString(map.values()));
//            settleFileService.save(settleFile);
//            settleDetailService.saveBatch(new ArrayList<>(map.values()));
//            if (!CollectionUtils.isEmpty(settleDistErrors)) {
//                settleDistErrorService.saveBatch(settleDistErrors);
//            }
//            first++;
//        }
//    }
//
//    /**
//     * 指令id生成器，25位，组成：前缀_4位随机因子_当前时间毫秒数，例：02_l5d0_00001604979731025
//     *
//     * @param prefix {@link String} 前缀：02_=划付，04_=分账
//     * @return {@link String}
//     */
//    private String settleIdHelper(String prefix) {
//        return prefix + getRandomCharSequence(4) + "_" + String.format("%017d", Instant.now().toEpochMilli());
//    }
//}